home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / drdobbs / 1989 / 09 / stevens.lst < prev   
File List  |  1989-07-27  |  15KB  |  606 lines

  1. _C PROGRAMMING COLUMN_
  2. by Al Stevens
  3.  
  4. [LISTING ONE]
  5.  
  6.  
  7.  
  8. // -------------- window.h
  9.  
  10. #ifndef WINDOWS
  11. #define WINDOWS
  12.  
  13. // ---------- screen dimensions
  14. #define SCREENWIDTH 80
  15. #define SCREENHEIGHT 25
  16.  
  17. // --------- atrribute values for colors
  18. enum color {
  19.     BLACK, BLUE, GREEN, CYAN, RED, MAGENTA, BROWN, LIGHTGRAY,
  20.     GRAY, LIGHTBLUE, LIGHTGREEN, LIGHTCYAN, LIGHTRED,
  21.     LIGHTMAGENTA, YELLOW, WHITE, BLINK = 128
  22. };
  23.  
  24. // ------------ spaces per tab stop (text displays)
  25. #define TABS 4
  26. // ------------ color assignments for window types
  27. #define YESNOFG  WHITE
  28. #define YESNOBG  GREEN
  29. #define NOTICEFG BLACK
  30. #define NOTICEBG CYAN
  31. #define ERRORFG  (YELLOW | BLINK)
  32. #define ERRORBG  RED
  33.  
  34. // ------------ a video window
  35. class Window {
  36.     unsigned bg, fg;        // window colors
  37.     unsigned lf,tp,rt,bt;   // window position
  38.     unsigned *wsave;        // video memory save buffer
  39.     unsigned *hsave;        // hide window save buffer
  40.     unsigned row, col;      // current cursor row and column
  41.     int tabs;               // tab stops, this window
  42.     char **text;            // window text content
  43. public:
  44.     Window(unsigned left, unsigned top,
  45.            unsigned right, unsigned bottom,
  46.            color wfg, color wbg);
  47.     ~Window(void);
  48.     void title(char *ttl);
  49.     Window& operator<<(char **btext);
  50.     Window& operator<<(char *ltext);
  51.     Window& operator<<(char ch);
  52.     void cursor(unsigned x, unsigned y);
  53.     void cursor(unsigned *x, unsigned *y)
  54.         { *y = row, *x = col; }
  55.     void clear_window(void);
  56.     void clreos(void);          // clear to end of screen
  57.     void clreol(void);          // clear to end of line
  58.     void hidewindow(void);      // hide an in-scope window
  59.     void restorewindow(void);   // unhide a hidden window
  60.     void page(void);            // page through the text
  61.     void scroll(int d);         // scroll the window up, down
  62.     void set_colors(int cfg, int cbg)   // change the colors
  63.         { fg = cfg, bg = cbg; }
  64.     void set_tabs(int t)        // change the tab stops
  65.         { if (t > 1 && t < 8) tabs = t; }
  66. };
  67.  
  68. // ---------- utility notice window
  69. class Notice : Window   {
  70. public:
  71.     Notice(char *text);
  72.     ~Notice(){}
  73. };
  74.  
  75. // ---------- utility yes/no window
  76. class YesNo : Window    {
  77. public:
  78.     YesNo(char *text);
  79.     ~YesNo(){}
  80.     int answer;
  81. };
  82.  
  83. // ---------- utility error window
  84. class Error : Window    {
  85. public:
  86.     Error(char *text);
  87.     ~Error(){}
  88. };
  89.  
  90. #define max(x,y) (((x) > (y)) ? (x) : (y))
  91. #define min(x,y) (((x) > (y)) ? (y) : (x))
  92.  
  93. #endif
  94.  
  95.  
  96. [LISTING TWO]
  97.  
  98. // -------------- window.c
  99.  
  100. // A C++ window library
  101.  
  102. #include <stddef.h>
  103. #include <string.h>
  104. #include <ctype.h>
  105. #include "window.h"
  106. #include "console.h"
  107.  
  108. #define HEIGHT (bt - tp + 1)
  109. #define WIDTH  (rt - lf + 1)
  110.  
  111. // ------- constructor for a Window
  112. Window::Window(unsigned left, unsigned top,     // 0 - 79, 0 - 24
  113.               unsigned right, unsigned bottom,
  114.               color wfg, color wbg)
  115. {
  116.     savecursor();
  117.     initconsole();
  118.     hidecursor();
  119.     // ----- adjust for windows beyond the screen dimensions
  120.     if (right > SCREENWIDTH-1)  {
  121.         left -= right-(SCREENWIDTH-1);
  122.         right = SCREENWIDTH-1;
  123.     }
  124.     if (bottom > SCREENHEIGHT-1)    {
  125.         top -= bottom-(SCREENHEIGHT-1);
  126.         bottom = SCREENHEIGHT-1;
  127.     }
  128.     // ------- initialize window dimensions
  129.     lf = left;
  130.     tp = top;
  131.     rt = right;
  132.     bt = bottom;
  133.     // ------- initialize window colors
  134.     fg = wfg;
  135.     bg = wbg;
  136.     // ------- initialize window cursor and tab stops
  137.     row = col = 0;
  138.     tabs = TABS;
  139.     // ---------- save the video rectangle under the new window
  140.     wsave = new unsigned[HEIGHT * WIDTH];
  141.     hsave = NULL;
  142.     savevideo(wsave, tp, lf, bt, rt);
  143.     // --------- draw the window frame
  144.     box(tp, lf, bt, rt, fg, bg);
  145.     // -------- clear the window text area
  146.     clear_window();
  147.     unhidecursor();
  148. }
  149.  
  150. // ------- destructor for a Window
  151. Window::~Window(void)
  152. {
  153.     // ----- restore the video RAM covered by the window
  154.     restorevideo(wsave, tp, lf, bt, rt);
  155.     delete wsave;
  156.     if (hsave != NULL)
  157.         delete hsave;
  158.     restorecursor();
  159. }
  160.  
  161. // ------- hide a window without destroying it
  162. void Window::hidewindow(void)
  163. {
  164.     if (hsave == NULL)  {
  165.         hsave = new unsigned[HEIGHT * WIDTH];
  166.         savevideo(hsave, tp, lf, bt, rt);
  167.         restorevideo(wsave, tp, lf, bt, rt);
  168.     }
  169. }
  170.  
  171. // --------- restore a hidden window
  172. void Window::restorewindow(void)
  173. {
  174.     if (hsave != NULL)  {
  175.         savevideo(wsave, tp, lf, bt, rt);
  176.         restorevideo(hsave, tp, lf, bt, rt);
  177.         delete hsave;
  178.         hsave = NULL;
  179.         colors(fg,bg);
  180.     }
  181. }
  182.  
  183. // -------- add a title to a window
  184. void Window::title(char *ttl)
  185. {
  186.     setcursor(lf + (WIDTH - strlen(ttl) - 1) / 2, tp);
  187.     colors(fg, bg);
  188.     window_printf(" %s ", ttl);
  189.     cursor(col, row);
  190. }
  191.  
  192. // ------- write text body to a window
  193. Window& Window::operator<<(char **btext)
  194. {
  195.     cursor(0, 0);
  196.     text = btext;
  197.     if (*btext != NULL)
  198.         *this << *btext++;
  199.     while (*btext != NULL && row < HEIGHT-3)
  200.         *this << '\n' << *btext++;
  201. }
  202.  
  203. // -------- write a line of text to a window
  204. Window& Window::operator<<(char *ltext)
  205. {
  206.     while (*ltext && col < WIDTH - 2 && row < HEIGHT - 2)
  207.         *this << *ltext++;
  208.     return *this;
  209. }
  210.  
  211. // -------- write a character to a window
  212. Window& Window::operator<<(char ch)
  213. {
  214.     cursor(col, row);
  215.     switch (ch) {
  216.         case '\n':
  217.             clreol();
  218.             if (row == HEIGHT-3)
  219.                 scroll(1);
  220.             else
  221.                 row++;
  222.         case '\r':
  223.             col = 0;
  224.             break;
  225.         case '\b':
  226.             if (col)
  227.                 --col;
  228.             break;
  229.         case '\t':
  230.             do
  231.                 *this << ' ';
  232.             while (col % tabs);
  233.             break;
  234.         default:
  235.             if (col == WIDTH - 2)
  236.                 *this << '\n';
  237.             colors(fg,bg);
  238.             window_putc(ch);
  239.             col++;
  240.             return *this;
  241.     }
  242.     cursor(col, row);
  243.     return *this;
  244. }
  245.  
  246. // ----- position the window cursor
  247. void Window::cursor(unsigned x, unsigned y)
  248. {
  249.     if (x < WIDTH-2 && y < HEIGHT-2)    {
  250.         setcursor(lf+1+x, tp+1+y);
  251.         row = y;
  252.         col = x;
  253.     }
  254. }
  255.  
  256. // ------ clear a window to all blamks
  257. void Window::clear_window(void)
  258. {
  259.     cursor(0,0);
  260.     clreos();
  261. }
  262.  
  263. // --- clear from current cursor position to end of window
  264. void Window::clreos(void)
  265. {
  266.     unsigned rw = row, cl = col;
  267.     clreol();
  268.     col = 0;
  269.     while (++row < HEIGHT-2)
  270.         clreol();
  271.     row = rw;
  272.     col = cl;
  273. }
  274.  
  275. // --- clear from current cursor position to end of line
  276. void Window::clreol(void)
  277. {
  278.     unsigned cl = col;
  279.     colors(fg,bg);
  280.     while (col < WIDTH-2)
  281.         *this << ' ';
  282.     col = cl;
  283. }
  284.  
  285. // ----- page and scroll through the text file
  286. void Window::page(void)
  287. {
  288.     int c = 0, lines = 0;
  289.     char **tx = text;
  290.  
  291.     hidecursor();
  292.     // ------ count the lines of text
  293.     while (*(tx + lines) != NULL)
  294.         lines++;
  295.     while (c != ESC)    {
  296.         c = getkey();
  297.         char **htext = text;
  298.         switch (c)  {
  299.             case UP:
  300.                 if (tx != text) {
  301.                     --tx;
  302.                     scroll(-1);
  303.                     unsigned x, y;
  304.                     cursor(&x, &y);
  305.                     cursor(0, 0);
  306.                     *this << *tx;
  307.                     cursor(x, y);
  308.                 }
  309.                 continue;
  310.             case DN:
  311.                 if (tx+HEIGHT-3 < text+lines-1) {
  312.                     tx++;
  313.                     scroll(1);
  314.                     unsigned x, y;
  315.                     cursor(&x, &y);
  316.                     cursor(0, HEIGHT-3);
  317.                     *this << *(tx + HEIGHT - 3);
  318.                     cursor(x, y);
  319.                 }
  320.                 continue;
  321.             case PGUP:
  322.                 tx -= HEIGHT-2;
  323.                 if (tx < text)
  324.                     tx = text;
  325.                 break;
  326.             case PGDN:
  327.                 tx += HEIGHT-2;
  328.                 if (tx+HEIGHT-3 < text+lines-1)
  329.                     break;
  330.             case END:
  331.                 tx = text+lines-(HEIGHT-2);
  332.                 if (tx > text)
  333.                     break;
  334.             case HOME:
  335.                 tx = text;
  336.                 break;
  337.             default:
  338.                 continue;
  339.         }
  340.         *this << tx;
  341.         text = htext;
  342.         clreos();
  343.     }
  344.     unhidecursor();
  345. }
  346.  
  347. // --------- scroll a window
  348. void Window::scroll(int d)
  349. {
  350.     videoscroll(d, tp+1, lf+1, bt-1, rt-1, fg, bg);
  351. }
  352.  
  353. // ------ utility notice window
  354. Notice::Notice(char *text)
  355.     : ((SCREENWIDTH-(strlen(text)+2)) / 2, 11,
  356.         ((SCREENWIDTH-(strlen(text)+2)) / 2) + strlen(text)+2,
  357.         14, NOTICEFG, NOTICEBG)
  358. {
  359.     *this << text << "\n Any key ...";
  360.     hidecursor();
  361.     getkey();
  362.     unhidecursor();
  363.     hidewindow();
  364. }
  365.  
  366. // ------ utility error window
  367. Error::Error(char *text)
  368.     : ( (SCREENWIDTH-(strlen(text)+2)) / 2, 11,
  369.         ((SCREENWIDTH-(strlen(text)+2)) / 2) + strlen(text)+2,
  370.         14, ERRORFG, ERRORBG)
  371. {
  372.     *this << text << "\n Any key ...";
  373.     hidecursor();
  374.     getkey();
  375.     unhidecursor();
  376.     hidewindow();
  377. }
  378.  
  379. // ------ utility yes/no window
  380. YesNo::YesNo(char *text)
  381.     : ( (SCREENWIDTH-(strlen(text)+10)) / 2, 11,
  382.         ((SCREENWIDTH-(strlen(text)+10)) / 2) + strlen(text)+10,
  383.         13, YESNOFG, YESNOBG)
  384. {
  385.     *this << text << "? (Y/N) ";
  386.     int c = 0;
  387.     hidecursor();
  388.     while (tolower(c) != 'y' && tolower(c) != 'n')
  389.         c = getkey();
  390.     unhidecursor();
  391.     hidewindow();
  392.     answer = tolower(c) == 'y';
  393. }
  394.  
  395.  
  396.  
  397. [LISTING THREE]
  398.  
  399. /* ----------- console.h -------- */
  400.  
  401. #ifndef CONSOLE
  402. #define CONSOLE
  403.  
  404. #include <disp.h>
  405.  
  406. // -------- cursor and keyboard functions (via BIOS)
  407. void hidecursor(void);
  408. void unhidecursor(void);
  409. void savecursor(void);
  410. void restorecursor(void);
  411. int getkey(void);
  412.  
  413. // -------- key values returned by getkey()
  414. #define BELL      7
  415. #define ESC      27
  416. #define UP      200
  417. #define BS      203
  418. #define FWD     205
  419. #define DN      208
  420. #define HOME    199
  421. #define END     207
  422. #define PGUP    201
  423. #define PGDN    209
  424.  
  425. #define attr(fg,bg) ((fg)+(((bg)&7)<<4))
  426.  
  427. // --------- video functions (defined as Zortech C++ equivalents)
  428. #define initconsole()            disp_open()
  429. #define closeconsole()           disp_flush()
  430. #define savevideo(bf,t,l,b,r)    disp_peekbox(bf,t,l,b,r)
  431. #define restorevideo(bf,t,l,b,r) disp_pokebox(bf,t,l,b,r)
  432. #define box(t,l,b,r,fg,bg)       disp_box(1,attr(fg,bg),t,l,b,r)
  433. #define colors(fg,bg)            disp_setattr(attr(fg,bg))
  434. #define setcursor(x,y)           disp_move(y,x)
  435. #define window_printf            disp_printf
  436. #define window_putc              disp_putc
  437. #define videoscroll(d,t,l,b,r,fg,bg) \
  438.         disp_scroll(d,t,l,b,r,attr(fg,bg));
  439.  
  440.  
  441. #endif
  442.  
  443.  
  444.  
  445. [LISTING FOUR]
  446.  
  447. /* ----------- console.c --------- */
  448.  
  449. /* PC-specific console functions */
  450.  
  451. #include <dos.h>
  452. #include <conio.h>
  453. #include "console.h"
  454.  
  455. /* ------- video BIOS (0x10) functions --------- */
  456. #define VIDEO         0x10
  457. #define SETCURSORTYPE 1
  458. #define SETCURSOR     2
  459. #define READCURSOR    3
  460. #define HIDECURSOR    0x20
  461.  
  462. #define SAVEDEPTH     20  /* depth to which cursors are saved */
  463.  
  464. static int cursorpos[SAVEDEPTH];
  465. static int cursorshape[SAVEDEPTH];
  466. static int sd;
  467.  
  468. union REGS rg;
  469.  
  470. /* ---- Low-level get cursor shape and position ---- */
  471. static void getcursor(void)
  472. {
  473.     rg.h.ah = READCURSOR;
  474.     rg.h.bh = 0;
  475.     int86(VIDEO,&rg,&rg);
  476. }
  477.  
  478. /* ---- Save the current cursor configuration ---- */
  479. void savecursor(void)
  480. {
  481.     getcursor();
  482.     if (sd < SAVEDEPTH) {
  483.         cursorshape[sd] = rg.x.cx;
  484.         cursorpos[sd++] = rg.x.dx;
  485.     }
  486. }
  487.  
  488. /* ---- Restore the saved cursor configuration ---- */
  489. void restorecursor(void)
  490. {
  491.     if (sd) {
  492.         rg.h.ah = SETCURSOR;
  493.         rg.h.bh = 0;
  494.         rg.x.dx = cursorpos[--sd];
  495.         int86(VIDEO,&rg,&rg);
  496.         rg.h.ah = SETCURSORTYPE;
  497.         rg.x.cx = cursorshape[sd];
  498.         int86(VIDEO,&rg,&rg);
  499.     }
  500. }
  501.  
  502. /* ---- Hide the cursor ---- */
  503. void hidecursor(void)
  504. {
  505.     getcursor();
  506.     rg.h.ch |= HIDECURSOR;
  507.     rg.h.ah = SETCURSORTYPE;
  508.     int86(VIDEO,&rg,&rg);
  509. }
  510.  
  511. /* ---- Unhide the cursor ---- */
  512. void unhidecursor(void)
  513. {
  514.     getcursor();
  515.     rg.h.ch &= ~HIDECURSOR;
  516.     rg.h.ah = SETCURSORTYPE;
  517.     int86(VIDEO,&rg,&rg);
  518. }
  519.  
  520. /* ---- Read a keystroke ---- */
  521. int getkey(void)
  522. {
  523.     rg.h.ah = 0;
  524.     int86(0x16,&rg,&rg);
  525.     if (rg.h.al == 0)
  526.         return (rg.h.ah | 0x80) & 255;
  527.     return rg.h.al & 255;
  528. }
  529.  
  530. [LISTING FIVE]
  531.  
  532. // ---------- look.c
  533.  
  534. // A C++ program to demonstrate the use of the window library.
  535. // This program lets you view a text file
  536.  
  537. #include <stdio.h>
  538. #include <string.h>
  539. #include <stream.hpp>
  540. #include <stdlib.h>
  541. #include "window.h"
  542.  
  543. #define MAXLINES 200            // maximum number of text lines
  544.  
  545. static char *wtext[MAXLINES+1]; // pointers to text lines
  546.  
  547. // --- taken from BS; handles all free store (heap) exhaustions
  548. void out_of_store(void);
  549. typedef void (*PF)();
  550. extern PF set_new_handler(PF);
  551.  
  552. main(int argc, char *argv[])
  553. {
  554.     set_new_handler(&out_of_store);
  555.     if (argc > 1)   {
  556.         // ---- open a full-screen window
  557.         Window wnd(0,0,79,24,CYAN,BLUE);
  558.         char ttl[80];
  559.         // ------ put the file name in the title
  560.         sprintf(ttl, "Viewing %s", argv[1]);
  561.         wnd.title(ttl);
  562.         filebuf buf;
  563.         if (buf.open(argv[1], input))   {
  564.             istream infile(&buf);
  565.             int t = 0;
  566.             // --- read the file and load the pointer array
  567.             char bf[120], *cp = bf;
  568.             while (t < MAXLINES && !infile.eof())   {
  569.                 infile.get(*cp);
  570.                 if (*cp != '\r')    {
  571.                     if (*cp == '\n')    {
  572.                         *cp = '\0';
  573.                         wtext[t] = new char [strlen(bf)+1];
  574.                         strcpy(wtext[t++], bf);
  575.                         cp = bf;
  576.                     }
  577.                     else
  578.                         cp++;
  579.                 }
  580.             }
  581.             wtext[t] = NULL;
  582.             // ---- write all the text to the window
  583.             wnd << wtext;
  584.             // ---- a YesNo window
  585.             YesNo yn("Continue");
  586.             if (yn.answer)
  587.                 wnd.page();
  588.             // ------ a Notice window
  589.             Notice nt("All done.");
  590.         }
  591.         else
  592.             // ------ error windows
  593.             Error err("No such file");
  594.     }
  595.     else
  596.         Error err("No file name specified");
  597. }
  598.  
  599. // ----- the BS free-store exhaustion handler
  600. void out_of_store(void)
  601. {
  602.     cerr << "operator new failed: out of store\n";
  603.     exit(1);
  604. }
  605.  
  606.